#ifndef CHaptikDevice_H
#define CHaptikDevice_H

#include "CMatrix3d.h"
#include "CVector3d.h"
#include "CGenericDevice.h"

#ifdef _WIN32
#include <windows.h>
#endif

#include <RSLib/Haptik.hpp>
using namespace RSLib;
using namespace RSLib::Math;

//Possible return values
const int RET_VAL_OK = 0;
const int RET_VAL_ALREADY = 1;
const int RET_VAL_DEFAULTDEVICE = 2;
//Possible error types - connection to library
const int RET_VAL_NOREFRESH = -1;
const int RET_VAL_NODEVICES = -2;
const int RET_VAL_DEVICENOTAVAILABLE = -3;
const int RET_VAL_DEFAULTNOTAVAILABLE = -4;
const int RET_VAL_LISTNOTREFRESHED = -5;
//Possible error types - connection to device
const int RET_VAL_SYSNOTAVAILABLE = -6;
const int RET_VAL_CANNOTINIT = -7;
const int RET_VAL_CANNOTSTART = -8;
const int RET_VAL_NORECALIBRATE = -9;
const int RET_VAL_SDK = -10;
const int RET_VAL_MEMORY = -11;

#define   FAIL(hresult) ((HRESULT(hresult)) < 0)
#define ADVICE(hresult) ((HRESULT(hresult)) > 0)

//Class to obtain an interface to HaptikLibrary,
//create a list of haptic devices
//and get a particular interface for one of them
class cHaptikDevice : public cGenericDevice{

public:

    //CONSTRUCTOR
	cHaptikDevice();

    //DESTRUCTOR
    virtual ~cHaptikDevice();

	//Main start function - connection to the library
	int startHaptik();

    //Get an haptic device after choice
	int getHaptikDevice(UINT32 a_inDevice);

	//Initialize the device (and calibrate it if it is necessary)
    virtual int initialize(const bool a_resetEncoders = false);

    //Open connection with device
    virtual int open();

    //Close connection with device
    virtual int close();

	//Release the obtainted interface and delete the pointer to it
	void release();

    //Commands to/from device
    int command(int a_command, void* a_data);

	//Modify or retreive some informations on the device
	int modifyDevice(int a_choose, void* a_data);

    //Device state, connected or not connected
	int getHapConnected() { return m_hapConnected; };

	//Get informations
	//General structure
	HaptikDeviceInfo getHaptikInfo() { return m_deviceInfo; };
	//Particular informations
	UINT32 getId() { return m_featuresDevice.m_deviceId; };
	const Char8* getName() { return m_featuresDevice.m_deviceName; };
	const Char8* getManufacturer() { return m_featuresDevice.m_deviceManufacturer; };
	const Char8* getModel() { return m_featuresDevice.m_deviceModel; };
	UINT32 getNumOfButtons() { return m_featuresDevice.m_numOfButtons; };
	UINT32 getCapabilities() { return m_featuresDevice.m_hwCapabilities; };
    //Get the interface to the device
	IHaptikDeviceInterface getInterface() { return m_hapticDevice; };

	//Return a string indicating the type of the error or advice
	const Char8* resultToString(int a_result);

	//Get the pointer to the Haptik Library interface
	Haptik* getPointerToLibrary() { return m_haptik; };

	//Control variables
    bool m_systemAvailable, m_systemReady;
	int m_defaultDevice;
	bool m_haptikStarted;

	//Type of the error (if generated) or simply advice
	int m_returnType;

	//Number of connected devices
	UINT32 m_numDevices;

	//Scale factors
	double m_scalePositionX;
	double m_scalePositionY;
	double m_scalePositionZ;

    protected:

	//Obtain the interface for the device
	int connectDevice(UINT32 a_numberDevice, bool a_correctChoice);

	//Haptik class object to get an interface to the library
    Haptik* m_haptik;

	//Interface with the device
	IHaptikDeviceInterface m_hapticDevice;

	//Basic features of the device
	struct BASIC_FEATURES{
	UINT32 m_deviceId;
	const Char8* m_deviceName;
	const Char8* m_deviceManufacturer;
	const Char8* m_deviceModel;
	UINT32 m_numOfButtons;
	UINT32 m_hwCapabilities;
	//Rate device
	Float32 m_rate;
	} m_featuresDevice;
	//Where the general informations are stored
	HaptikDeviceInfo m_deviceInfo;

	//Space characteristics
	struct DEVICE_WORKSPACE{
	float m_maxWorkspaceX;
	float m_minWorkspaceX;
	float m_maxWorkspaceY;
	float m_minWorkspaceY;
	float m_maxWorkspaceZ;
	float m_minWorkspaceZ;
	Vector3<Float32> m_maxWorkspace;
	float4x4 m_originalMatrix;
	} m_wokspaceDevice;

	//Force and torque characteristics
	struct FORCE_TORQUE_DEVICE{
	float m_maxForce;
	float m_maxTorque;
	} m_forceAndTorqueDevice;
    
	double m_scaleForce;
	double m_scaleTorque;

	//Is the interface connected?
    int m_hapConnected;

	//Read/write data
	HaptikData m_data;

	//Informations about the library
	HaptikLibraryInfo m_libraryInfo;

	struct LIBRARY_INFO{
		const Char8* m_libCompany;
		const Char8* m_libName;
		const Char8* m_libVersion;
	} m_infoLibrary;

};

#endif